package com.gxa.luckin.order.service.impl;

import com.gxa.luckin.core.exception.BusinessException;
import com.gxa.luckin.core.exception.MessageCode;
import com.gxa.luckin.core.pojo.Shop;
import com.gxa.luckin.core.pojo.Sku;
import com.gxa.luckin.core.utils.SnowFlake;
import com.gxa.luckin.order.dto.OrderDTO;
import com.gxa.luckin.order.enums.OrderStatusEnum;
import com.gxa.luckin.order.pojo.CartItem;
import com.gxa.luckin.order.pojo.Order;
import com.gxa.luckin.order.pojo.OrderItem;
import com.gxa.luckin.order.pojo.OrderStatus;
import com.gxa.luckin.order.repository.OrderItemRepository;
import com.gxa.luckin.order.repository.OrderRepository;
import com.gxa.luckin.order.repository.OrderStatusRepository;
import com.gxa.luckin.order.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Example;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.util.ObjectUtils;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.transaction.Transactional;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * @author: XHZ
 * @date: 16:01 2021/7/16
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {
/*
    @Resource
    private CartService cartService;
*/
/*
    @Resource
    private UserService userService;*//*


    @Resource
    private SkuService skuService;
*/

    @Resource
    private OrderRepository orderRepository;

    @Resource
    private OrderStatusRepository orderStatusRepository;

    @Resource
    private OrderItemRepository orderItemRepository;

    @Override
    @Transactional
    public String createOrder(Long userId, OrderDTO orderDTO, Integer shopId) throws BusinessException, URISyntaxException {
        //生成订单id
        String orderId = SnowFlake.nextId() + "";

        log.info("orderId is{}", orderId);

        //之所以先插入订单项是因为要计算订单总价，一次循环搞定，免得写两个循环  因为订单id是程序生成 所以顺序不影响
        //计算订单总价,减库存，分别插入订单项
        Long orderAmount = 0L;
        for (String skuId : orderDTO.getSkuIds()) {

            RestTemplate restTemplate = new RestTemplate();

            URI uri = new URI("http://localhost:8004/sku/" + skuId);
//            MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
//            paramMap.add("id", String.valueOf(skuId));
            Sku sku = restTemplate.getForObject(uri, Sku.class);

//            Sku sku = skuService.findById(skuId);

            if (ObjectUtils.isEmpty(sku)) {
                log.error("下单商品不存在,itemId:{}", skuId);
                throw new BusinessException(MessageCode.GOODS_IS_EMPTY);
            }
            //根据skuid查询购物项

            URI uri1 = new URI("http://localhost:8003/cart/queryUserCartItem");
            MultiValueMap<String, Object> paramMap1 = new LinkedMultiValueMap<>();
            paramMap1.add("userId", userId);
            paramMap1.add("skuId", sku.getId());
            CartItem cartItem = restTemplate.postForObject(uri1, paramMap1, CartItem.class);

//            CartItem cartItem = cartService.queryUserCartItem(userId, sku.getId());

            if (ObjectUtils.isEmpty(cartItem)) {
                log.error("下单商品不存在,itemId:{}", skuId);
                throw new BusinessException(MessageCode.GOODS_IS_EMPTY);
            }

            // 扣库存   seata解决分布式事务
//            skuService.updateItemStock(cartItem.getNum(), skuId);

            // 购物项的数量*sku的最新价格
            orderAmount = orderAmount + (cartItem.getNum() * sku.getPrice());

            // 分别写入订单项信息
            createOrderItem(orderId, skuId, sku, cartItem);
            log.debug("decreaseStock,itemId {},num {}", sku, cartItem.getNum());


            //删除该sku在购物车的信息  TODO 方便测试暂时注释
            //cartService.removeCartItem(userId,skuId);

        }


        //保存订单基本信息
        createOrder(orderDTO, orderId, orderAmount, userId, shopId);
/*        //保存收货地址
        createShipping(orderDTO, orderId);*/
        //保存订单状态
        createOrderStatus(orderId);

        return orderId;
    }

    @Override
    public Order queryOrderById(String id) {
        return orderRepository.findOrderByOrderId(id);
    }

    @Override
    public OrderStatus queryOrderStatus(String id) {
        return orderStatusRepository.findOrderStatusByOrderId(id);
    }

    @Override
    public Boolean updateOrderStatus(String orderId, Integer status) {

        OrderStatus orderStatus = orderStatusRepository.findOrderStatusByOrderId(orderId);

        if (status < OrderStatusEnum.NO_PAYMENT.getCode() || status > OrderStatusEnum.RATE.getCode()) {
            log.error("修改状态为非法状态!");
            return false;
        }
        if (orderStatus.getStatus().equals(status)) {
            log.error("修改订单状态与原状态一致，无需修改!");
            return false;
        }
        Integer result = orderStatusRepository.changeOrderState(status, orderId, orderStatus.getStatus());
        if (result > 0) {
            return true;
        } else {
            return false;
        }
    }


    private void createOrder(OrderDTO orderDTO, String orderId, Long orderAmount, Long userId, Integer shopId) throws URISyntaxException {
        Order order = new Order();
        order.setOrderId(orderId);
//        order.setPostFee(0L);
        //TODO 包邮规则后期应该做成专门业务，此处待完善
        if (orderAmount < 8000) {
            //订单满80包邮,不足20元邮费
//            order.setPostFee(2000L);
        }
        //实付金额
//        order.setActualPay(orderAmount + order.getPostFee());

        //TODO 如果后期促销规则 实际支付可以减得
        //总金额
//        order.setTotalPay(orderAmount + order.getPostFee());

//        order.setBuyerMessage(orderDTO.getBuyerMessage());
        //未评价
//        order.setBuyerRate(0);
        //支付方式
//        order.setPaymentType(orderDTO.getPaymentType());
        order.setCreateTime(new Date());
        order.setUserId(userId);
        //发票类型
//        order.setInvoiceType(orderDTO.getInvoiceType());
//        order.setSourceType(orderDTO.getSourceType());

        RestTemplate restTemplate = new RestTemplate();
        URI uri = new URI("http://localhost:8001/shop/shopById");
        MultiValueMap<String, Object> paramMap = new LinkedMultiValueMap<>();
        paramMap.add("id", shopId);
        Shop shop = restTemplate.postForObject(uri, paramMap, Shop.class);

        order.setShopId(shopId);
        order.setShopName(Objects.requireNonNull(shop).getName());
        order.setShopAddress(shop.getAddress());
        //写入订单信息
        log.debug("crate order is {}", order);
        orderRepository.save(order);
    }

    private void createOrderStatus(String orderId) {
        //保存订单状态
        OrderStatus orderStatus = new OrderStatus();
        orderStatus.setOrderId(orderId);
        orderStatus.setStatus(OrderStatusEnum.NO_PAYMENT.getCode());
        orderStatus.setCreateTime(new Date());
        //设置订单超时时间
        //下单时间+12小时  43200000=12小时
        orderStatus.setPaymentTime(new Date(new Date().getTime() + 43200000));
        log.debug("create orderStatus : {}", orderStatus);
        orderStatusRepository.save(orderStatus);
    }

    private void createOrderItem(String orderId, String skuId, Sku sku, CartItem cartItem) {
        OrderItem orderItem = new OrderItem();
        orderItem.setImage(cartItem.getImage());
        orderItem.setSkuId(skuId);
        orderItem.setOrderId(orderId);
        orderItem.setPrice(cartItem.getNum() * sku.getPrice());
        orderItem.setName(sku.getName());
        orderItem.setNum(cartItem.getNum());
        log.debug("create orderItem : {}", orderItem);
        //写入订单详情
        orderItemRepository.save(orderItem);
    }

    //分布式事务  需要加库存
    @Transactional
    @Override
    public void cancelOrder(String orderId) {

        //1.设置订单状态为交易关闭
        updateOrderStatus(orderId, OrderStatusEnum.NO_PAYMENT.getCode());

        //2.查询该订单所有订单项
        List<OrderItem> orderItemList = orderItemRepository.findOrderItemByOrderId(orderId);

        //3.遍历订单项加回库存
        orderItemList.forEach(orderItem -> {
//            skuService.addItemStock(orderItem.getNum(), orderItem.getSkuId());
        });

    }

    @Override
    public List<OrderItem> queryOrderItemByOrderId(String orderId) {
        return orderItemRepository.findOrderItemByOrderId(orderId);
    }

    @Override
    public List<Order> queryAllByUserId(Long userId) {

        return orderRepository.queryAllByUserId (userId);
    }
}
